/*
 * Copyright 2012 Andrea Parodi
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package eban.storebyrules;

import com.google.common.base.Ascii;
import com.google.common.base.Preconditions;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.testng.Assert;
import org.testng.annotations.Test;
import sun.util.calendar.ZoneInfo;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.UUID;

public abstract class AbstractTestDbManager {
    public abstract Storage getDb(String location);



    public static final String DB_LOCATION = "TestSqliteDbManager";

    @AllArgsConstructor
    class Relation{
        @Persistent @Getter @Setter
        private String description;

        @Key @Getter @Setter
        private Integer key;
    }


    public AbstractTestDbManager() {
        manager = getDb(DB_LOCATION);
        model = manager.addModel(Relation.class);
        Assert.assertNotNull(model);
        Assert.assertNotNull(manager);
    }

    @Test(groups = "performance",enabled = false)
    public void testPerformanceInsert(){

        Transaction transaction = model.getStorage().beginTransaction();
        model.clear(transaction);
        Relation r=null;
        for (int i=0;i< 1000000;i++){
            String description = UUID.randomUUID().toString().replace("-", "").substring(0, 6);

            r = new Relation(description, i);
            model.store(transaction, r);
            if (i%10000==0)
                System.out.println(i);
        }
        transaction.commit();
    }

    @Test(groups = "performance",enabled = false)
    public void testPerformanceInsertComparison(){

        Transaction transaction = model.getStorage().beginTransaction();
        model.clear(transaction);
        Relation r=null;
        String cmd="INSERT INTO RELATION (DESCRIPTION,KEY) VALUES ('%s','%s')\r\n";
        for (int i=0;i< 1000000;i++){
            String description = UUID.randomUUID().toString().replace("-", "").substring(0, 6);

            //r = new Relation(description, key);
            transaction.execute(String.format(cmd,description, i));

            if (i%10000==0)
                System.out.println(i);
        }
        transaction.commit();
    }


    private final Storage manager;
    private final PersistentCollection<Relation> model;


    public void close(PersistentCollectionImpl<?> model) {
        model.getStorage().close();
    }

    @Test(groups = "unit")
    public void testInstanceAreStored() {

        final List<Relation> relations = storeObjectAndRetrieveAll();
        Assert.assertEquals(relations.size(), 1);

    }



    @Test(groups = "unit")
    public void testIntPrimitiveField() {

        final List<Relation> relations = storeObjectAndRetrieveAll();
        Assert.assertEquals(relations.get(0).getKey(), Integer.valueOf(11));


    }

    @Test(groups = "unit")
    public void testLongType() {
        new BaseFieldTypeTest<Long>(getDb("Long"), -121212121212121212L, 121212121212121212L, 9121212121212121212L) {
        }.runAllTests();
    }

    @Test(groups = "unit")
    public void testBigIntegerType() {
        new BaseFieldTypeTest<BigInteger>(getDb("BigInteger"),
                BigInteger.valueOf(-121212121212121212L),
                BigInteger.valueOf(121212121212121212L),
                BigInteger.valueOf(921212121212121212L)) {
        }.runAllTests();
    }


    @Test(groups = "unit")
    public void testIntType() {
        new BaseFieldTypeTest<Integer>(getDb("Int"), -1212121212, 212121212, 512121212)
     {}.runAllTests();}

    @Test(groups = "unit") public void testShortType() {
        new BaseFieldTypeTest<Short>(getDb("Short"), Integer.valueOf(-1212).shortValue(), Integer.valueOf(1212).shortValue(), Integer.valueOf(3212).shortValue()) {
        }.runAllTests();
    }

    @Test(groups = "unit") public void testByteType() {
        new BaseFieldTypeTest<Byte>(getDb("Byte"), (byte) -12, (byte) 12, (byte) 26) {
        }.runAllTests();
    }

    @Test(groups = "unit") public void testBigDecimalType() {
        new BaseFieldTypeTest<BigDecimal>(getDb("BigDecimal"), BigDecimal.valueOf(-121212.3253), BigDecimal.valueOf(121212.3253), BigDecimal.valueOf(821212.3253)) {
        }.runAllTests();
    }

    @Test(groups = "unit") public void testFloatType() {
        new BaseFieldTypeTest<Float>(getDb("Float"), -12.54656f, 12.54656f, 72.54656f) {
        }.runAllTests();
    }

    @Test(groups = "unit") public void testDoubleType() {
        new BaseFieldTypeTest<Double>(getDb("Double"), -12.54656, 12.54656, 62.54656) {
        }.runAllTests();
    }

    @Test(groups = "unit") public void testStringType() {
        new BaseFieldTypeTest<String>(getDb("String"), "AAA", "Rhis is a test string type", "ZZZZZZ") {
        }.runAllTests();
    }


    @Test(groups = "unit") public void testStringBufferType() {
        new BaseFieldTypeTest<StringBuffer>(getDb("StringBuffer"), new StringBuffer("AAA"), new StringBuffer("This is a test string type"), new StringBuffer("ZZZZZZ")) {
        }.runAllTests();
    }

    @Test(groups = "unit") public void testStringBuilderType() {
        new BaseFieldTypeTest<StringBuilder>(getDb("StringBuilder"), new StringBuilder("AAA"), new StringBuilder("This is a test string type"), new StringBuilder("ZZZZZZ")) {
        }.runAllTests();
    }

    @Test(groups = "unit") public void testCharType() {
        new BaseFieldTypeTest<Character>(getDb("Character"), 'A', 'T', 'Z') {
        }.runAllTests();
    }

    @Test(groups = "unit") public void testClassType() {
        new BaseFieldTypeTest<Class>(getDb("Class"), Ascii.class, Preconditions.class, ZoneInfo.class) {
        }.runAllTests();
    }

    @Test(groups = "unit") public void testReferenceValueType() {


        new BaseFieldTypeTest<User>(getDb("User"), new User("Andrea"), new User("Giuseppe"), new User("Zirconio")) {
        }.runAllTests();
    }

    private List<Relation> storeObjectAndRetrieveAll() {
        Relation r = new Relation("test relation", 11);
        Assert.assertNotNull(model);
        Assert.assertNotNull(model.getStorage());
        Transaction transaction = model.getStorage().beginTransaction();
        model.detach(r);
        model.clear(transaction);
        model.store(transaction, r);
        transaction.commit();
        return model.load();
    }


}
